package com.gamecollection.minesweeper.model;

import com.gamecollection.mvc.Model;
import com.gamecollection.minesweeper.utils.GameUtils;

import java.util.Random;

/**
 * 扫雷游戏模型
 */
public class MinesweeperModel implements Model {
    
    // 游戏状态
    private int gameState = GameUtils.STATE_SELECT_LEVEL;
    
    // 游戏难度
    private int level = 0; // 0: 简单, 1: 中等, 2: 困难
    
    // 游戏参数
    private int mapWidth;
    private int mapHeight;
    private int mineCount;
    private int flagCount = 0;
    
    // 游戏数据
    private int[][] bottomData; // 底层数据: -1雷, 0空, 1-8数字
    private int[][] topData;    // 顶层数据: -1无覆盖, 0覆盖, 1插旗, 2差错旗
    
    // 游戏时间
    private long startTime;
    private long endTime;
    
    // 鼠标状态
    private int mouseX;
    private int mouseY;
    private boolean leftClick = false;
    private boolean rightClick = false;
    
    public MinesweeperModel() {
        setLevel(0); // 默认简单难度
    }
    
    @Override
    public void initialize() {
        gameState = GameUtils.STATE_SELECT_LEVEL;
        level = 0;
        flagCount = 0;
        setLevel(0);
        startTime = System.currentTimeMillis();
        endTime = startTime;
    }
    
    @Override
    public void update() {
        if (gameState == GameUtils.STATE_PLAYING) {
            endTime = System.currentTimeMillis();
            processInput();
            checkGameState();
        }
    }
    
    @Override
    public void reset() {
        initialize();
        generateMines();
        resetTopData();
    }
    
    @Override
    public int getGameState() {
        return gameState;
    }
    
    @Override
    public void setGameState(int state) {
        this.gameState = state;
    }
    
    /**
     * 设置游戏难度
     */
    public void setLevel(int level) {
        this.level = level;
        switch (level) {
            case 0: // 简单
                mapWidth = GameUtils.EASY_WIDTH;
                mapHeight = GameUtils.EASY_HEIGHT;
                mineCount = GameUtils.EASY_MINES;
                break;
            case 1: // 中等
                mapWidth = GameUtils.MEDIUM_WIDTH;
                mapHeight = GameUtils.MEDIUM_HEIGHT;
                mineCount = GameUtils.MEDIUM_MINES;
                break;
            case 2: // 困难
                mapWidth = GameUtils.HARD_WIDTH;
                mapHeight = GameUtils.HARD_HEIGHT;
                mineCount = GameUtils.HARD_MINES;
                break;
        }
        
        // 初始化数据数组
        bottomData = new int[mapWidth + 2][mapHeight + 2];
        topData = new int[mapWidth + 2][mapHeight + 2];
        
        // 生成地雷
        generateMines();
        // 计算数字
        calculateNumbers();
        // 重置顶层数据
        resetTopData();
    }
    
    /**
     * 生成地雷
     */
    private void generateMines() {
        Random random = new Random();
        int minesPlaced = 0;
        
        while (minesPlaced < mineCount) {
            int x = random.nextInt(mapWidth) + 1;
            int y = random.nextInt(mapHeight) + 1;
            
            if (bottomData[x][y] != -1) {
                bottomData[x][y] = -1;
                minesPlaced++;
            }
        }
    }
    
    /**
     * 计算数字
     */
    private void calculateNumbers() {
        for (int i = 1; i <= mapWidth; i++) {
            for (int j = 1; j <= mapHeight; j++) {
                if (bottomData[i][j] != -1) {
                    int count = 0;
                    for (int di = -1; di <= 1; di++) {
                        for (int dj = -1; dj <= 1; dj++) {
                            if (bottomData[i + di][j + dj] == -1) {
                                count++;
                            }
                        }
                    }
                    bottomData[i][j] = count;
                }
            }
        }
    }
    
    /**
     * 重置顶层数据
     */
    private void resetTopData() {
        for (int i = 1; i <= mapWidth; i++) {
            for (int j = 1; j <= mapHeight; j++) {
                topData[i][j] = 0;
            }
        }
        flagCount = 0;
    }
    
    /**
     * 处理输入
     */
    private void processInput() {
        if (leftClick) {
            handleLeftClick();
            leftClick = false;
        }
        if (rightClick) {
            handleRightClick();
            rightClick = false;
        }
    }
    
    /**
     * 处理左键点击
     */
    private void handleLeftClick() {
        int gridX = getGridX();
        int gridY = getGridY();
        
        if (isValidGrid(gridX, gridY)) {
            if (topData[gridX][gridY] == 0) {
                // 翻开格子
                topData[gridX][gridY] = -1;
                if (bottomData[gridX][gridY] == 0) {
                    // 如果是空格，递归翻开周围的格子
                    openSpace(gridX, gridY);
                }
            } else if (topData[gridX][gridY] == -1) {
                // 如果已经翻开，尝试数字翻开
                openNumber(gridX, gridY);
            }
        }
    }
    
    /**
     * 处理右键点击
     */
    private void handleRightClick() {
        int gridX = getGridX();
        int gridY = getGridY();
        
        if (isValidGrid(gridX, gridY)) {
            if (topData[gridX][gridY] == 0) {
                // 插旗
                topData[gridX][gridY] = 1;
                flagCount++;
            } else if (topData[gridX][gridY] == 1) {
                // 取消插旗
                topData[gridX][gridY] = 0;
                flagCount--;
            }
        }
    }
    
    /**
     * 获取网格X坐标
     */
    private int getGridX() {
        if (mouseX > GameUtils.OFFSET && mouseY > 3 * GameUtils.OFFSET) {
            return (mouseX - GameUtils.OFFSET) / GameUtils.SQUARE_LENGTH + 1;
        }
        return 0;
    }
    
    /**
     * 获取网格Y坐标
     */
    private int getGridY() {
        if (mouseX > GameUtils.OFFSET && mouseY > 3 * GameUtils.OFFSET) {
            return (mouseY - GameUtils.OFFSET * 3) / GameUtils.SQUARE_LENGTH + 1;
        }
        return 0;
    }
    
    /**
     * 检查网格坐标是否有效
     */
    private boolean isValidGrid(int x, int y) {
        return x >= 1 && x <= mapWidth && y >= 1 && y <= mapHeight;
    }
    
    /**
     * 翻开空格
     */
    private void openSpace(int x, int y) {
        for (int i = x - 1; i <= x + 1; i++) {
            for (int j = y - 1; j <= y + 1; j++) {
                if (isValidGrid(i, j) && topData[i][j] != -1) {
                    if (topData[i][j] == 1) {
                        flagCount--;
                    }
                    topData[i][j] = -1;
                    if (bottomData[i][j] == 0) {
                        openSpace(i, j);
                    }
                }
            }
        }
    }
    
    /**
     * 数字翻开
     */
    private void openNumber(int x, int y) {
        if (bottomData[x][y] > 0) {
            int flagCount = 0;
            for (int i = x - 1; i <= x + 1; i++) {
                for (int j = y - 1; j <= y + 1; j++) {
                    if (topData[i][j] == 1) {
                        flagCount++;
                    }
                }
            }
            
            if (flagCount == bottomData[x][y]) {
                for (int i = x - 1; i <= x + 1; i++) {
                    for (int j = y - 1; j <= y + 1; j++) {
                        if (isValidGrid(i, j) && topData[i][j] != 1) {
                            topData[i][j] = -1;
                            if (bottomData[i][j] == 0) {
                                openSpace(i, j);
                            }
                        }
                    }
                }
            }
        }
    }
    
    /**
     * 检查游戏状态
     */
    private void checkGameState() {
        // 检查是否踩雷
        for (int i = 1; i <= mapWidth; i++) {
            for (int j = 1; j <= mapHeight; j++) {
                if (bottomData[i][j] == -1 && topData[i][j] == -1) {
                    gameState = GameUtils.STATE_GAME_OVER;
                    showAllMines();
                    return;
                }
            }
        }
        
        // 检查是否胜利
        int coveredCount = 0;
        for (int i = 1; i <= mapWidth; i++) {
            for (int j = 1; j <= mapHeight; j++) {
                if (topData[i][j] != -1) {
                    coveredCount++;
                }
            }
        }
        
        if (coveredCount == mineCount) {
            gameState = GameUtils.STATE_WIN;
            // 自动插旗
            for (int i = 1; i <= mapWidth; i++) {
                for (int j = 1; j <= mapHeight; j++) {
                    if (topData[i][j] == 0) {
                        topData[i][j] = 1;
                    }
                }
            }
        }
    }
    
    /**
     * 显示所有地雷
     */
    private void showAllMines() {
        for (int i = 1; i <= mapWidth; i++) {
            for (int j = 1; j <= mapHeight; j++) {
                if (bottomData[i][j] == -1 && topData[i][j] != 1) {
                    topData[i][j] = -1;
                }
                if (bottomData[i][j] != -1 && topData[i][j] == 1) {
                    topData[i][j] = 2; // 差错旗
                }
            }
        }
    }
    
    // Getter和Setter方法
    public int getLevel() {
        return level;
    }
    
    public int getMapWidth() {
        return mapWidth;
    }
    
    public int getMapHeight() {
        return mapHeight;
    }
    
    public int getMineCount() {
        return mineCount;
    }
    
    public int getFlagCount() {
        return flagCount;
    }
    
    public int[][] getBottomData() {
        return bottomData;
    }
    
    public int[][] getTopData() {
        return topData;
    }
    
    public long getStartTime() {
        return startTime;
    }
    
    public long getEndTime() {
        return endTime;
    }
    
    public int getWidth() {
        // 计算精确的窗口宽度：边距 + 网格宽度 + 边距
        return 2 * GameUtils.OFFSET + mapWidth * GameUtils.SQUARE_LENGTH + 20; // 额外20像素用于边框和边距
    }
    
    public int getHeight() {
        // 计算精确的窗口高度：信息栏 + 边距 + 网格高度 + 边距
        return 3 * GameUtils.OFFSET + mapHeight * GameUtils.SQUARE_LENGTH + 20; // 额外20像素用于边框和边距
    }
    
    public void setMousePosition(int x, int y) {
        this.mouseX = x;
        this.mouseY = y;
    }
    
    public void setLeftClick(boolean leftClick) {
        this.leftClick = leftClick;
    }
    
    public void setRightClick(boolean rightClick) {
        this.rightClick = rightClick;
    }
} 